package com.moyq5.wifi.joystick.worker;

import android.content.Context;

import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

import com.moyq5.wifi.joystick.Console;
import com.moyq5.wifi.joystick.ConsoleFactory;
import com.moyq5.wifi.joystick.worker.netty.handler.DiscardClientHandler;

import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;


/**
 * Netty服务
 * @author mo_yq5
 */
public class NettyClientWorker extends Worker {
    private static final Console console = ConsoleFactory.get(NettyClientWorker.class);

    private static final EventLoopGroup workerGroup = new NioEventLoopGroup();
    private static final Bootstrap bootstrap = new Bootstrap();
    private static final Set<ChannelFuture> channelFutures = Collections.newSetFromMap(
            new ConcurrentHashMap<>());

    static {
        bootstrap.group(workerGroup)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.TCP_FASTOPEN_CONNECT, true)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.SO_TIMEOUT, 5)
                .option(ChannelOption.SO_REUSEADDR, true)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,1000)
                .option(ChannelOption.ALLOW_HALF_CLOSURE, false)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new DiscardClientHandler());
                    }
                });
    }

    public NettyClientWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork() {
        String host = getInputData().getString("host");
        int port = getInputData().getInt("port", 8080);
        connect(host, port);
        return Result.success();
    }

    private void connect(final String host, final int port) {
        console.info("Netty 连接：%s %d", host, port);
        ChannelFuture connectFuture = bootstrap.connect(host, port);
        connectFuture.addListener(future -> {
            if (future.isSuccess()) {
                console.info("Netty 连接成功：%s", connectFuture.channel().remoteAddress().toString());
            } else {
                console.info("Netty 连接失败：%s", connectFuture.channel().remoteAddress().toString());
            }
        });
        ChannelFuture closeFuture = connectFuture.channel().closeFuture();
        channelFutures.add(closeFuture);
        closeFuture.addListener(future -> {
            if (future.isDone()) {
                console.error("Netty 连接断开：%s", closeFuture.channel().remoteAddress().toString());
                connect(host, port);
            }
        });
    }

}
